#include "SampleTextureSphere.h"
#include "GLUtils.h"
#include "LogUtils.h"
#include "math.h"
#include <gtc/matrix_transform.hpp>

// 圆锥

SampleTextureSphere::SampleTextureSphere() {
    m_MVPMatLoc = GL_NONE;
    m_AngleX = 90;
    m_AngleY = 0;

    m_ScaleX = 0.88f;
    m_ScaleY = 0.88f;

    m_TextureId = 0;
}

SampleTextureSphere::~SampleTextureSphere() {
    delete [] m_TextureArray;
    delete [] m_VerticesArray;
    delete [] m_ColorArray;
    NativeImageUtil::FreeNativeImage(&m_RenderImage);
}

void SampleTextureSphere::LoadImage(NativeImage *pImage) {
    LOGCATE("SampleTextureSphere::LoadImage pImage = %p", pImage->ppPlane[0]);
    if (pImage)
    {
        LOGCATE("SampleTextureSphere::LoadImage w:%d h:%d", pImage->width, pImage->height);
        m_RenderImage.width = pImage->width;
        m_RenderImage.height = pImage->height;
        m_RenderImage.format = pImage->format;
        NativeImageUtil::CopyNativeImage(pImage, &m_RenderImage);
    }
}

void SampleTextureSphere::Init() {
    //create RGBA texture
    glGenTextures(1, &m_TextureId);
    glBindTexture(GL_TEXTURE_2D, m_TextureId);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);

    char vShaderStr[] =
            "#version 300 es                          \n"
            "layout(location = 0) in vec4 vPosition;  \n"
            "layout(location = 1) in vec2 a_texCoord;   \n"
            "out vec2 v_texCoord;                       \n"
            "uniform mat4 u_MVPMatrix;\n"
            "void main()                              \n"
            "{                                        \n"
            "   gl_Position = u_MVPMatrix * vPosition;              \n"
            "   v_texCoord = a_texCoord;                \n"
            "}                                        \n";

    char fShaderStr[] =
            "#version 300 es                              \n"
            "precision highp float;                     \n"
            "in vec2 v_texCoord;                                 \n"
            "layout(location = 0) out vec4 outColor;             \n"
            "uniform sampler2D s_TextureMap;                     \n"
            "void main()                                  \n"
            "{                                            \n"
            "  outColor = texture(s_TextureMap, v_texCoord);     \n"
            "}                                            \n";

    m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
    if (m_ProgramObj){
        m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap");
        m_MVPMatLoc = glGetUniformLocation(m_ProgramObj, "u_MVPMatrix");
    }
    m_VerticesArray = createPositions();
    m_ColorArray = createColors();
//    circularVertices = createCircularPositions();
//    circularColorVertices = createCircularColors();
    UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, (float)m_ratio);
    glEnable(GL_DEPTH_TEST);
}

void SampleTextureSphere::Draw() {
//    GLushort indices[6] = {0, 1, 2, 0, 2, 3};

    if (m_ProgramObj == 0 || m_TextureId == GL_NONE)
        return;
    LOG_DEBUG("SampleTextureSphere::Draw w:%d h:%d\n", m_RenderImage.width, m_RenderImage.height);

    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0, 1.0, 1.0, 1.0);

    //upload RGBA image data
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_TextureId);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
            m_RenderImage.width, m_RenderImage.height, 0,
            GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);

    // Use the program object
    glUseProgram(m_ProgramObj);

    // Load the vertex data
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, m_VerticesArray);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, m_TextureArray);
    glEnableVertexAttribArray(1);

    // Bind the RGBA map
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_TextureId);
    // Set the RGBA map sampler to texture unit to 0
    glUniform1i(m_SamplerLoc, 0);

    glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, circularPixCount);
//    glDrawArrays(GL_TRIANGLE_FAN, 0, circularPixCount);
//    glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(GLushort), GL_UNSIGNED_SHORT, indices);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

//    // 圆形
//    glUseProgram(m_ProgramObj);
//
//    // Load the vertex data
//    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, circularVertices);
//    glEnableVertexAttribArray(0);
//
//    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, circularColorVertices);
//    glEnableVertexAttribArray(1);
//
//    glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
//    glDrawArrays(GL_TRIANGLE_FAN, 0, circularPixCount);
////    glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(GLushort), GL_UNSIGNED_SHORT, indices);
//
//    glDisableVertexAttribArray(0);
//    glDisableVertexAttribArray(1);
}

void SampleTextureSphere::Destroy() {
    if (m_ProgramObj) {
        glDeleteProgram(m_ProgramObj);
        glDeleteTextures(1, &m_TextureId);
        m_ProgramObj = GL_NONE;
    }
}

void SampleTextureSphere::setParentViewSize(int w, int h) {
    m_ParentViewWidth = w;
    m_ParentViewHeight = h;
    m_ratio = (float)w/h;

    GLfloat x = 0.5 * w / h;
    LOG_DEBUG("SampleTextureSphere::setParentViewSize w:%d h:%d x%f \n", w, h, x);

//    circularVertices[1] = circularVertices[10]  = x;
//    circularVertices[4] = circularVertices[7] = 0-x;
}
void SampleTextureSphere::OnSurfaceCreated() {
    glEnable(GL_DEPTH_TEST);
}
void SampleTextureSphere::OnSurfaceChanged(int width, int height) {
    setParentViewSize(width, height);
}

GLfloat*  SampleTextureSphere::createPositions() {
    int index = 0, textureIndex = 0, count = 0;

    GLfloat* data = new GLfloat[circularPixCount*3];
    m_TextureArray = new GLfloat[circularPixCount*2];
    float step = 5.0f;
    float r1,r2;
    float h1,h2;
    float sinV,cosV;
    int wd=0, jd=0;
//    float wdOne = 0.166666667f;
//    float jdOne = 0.083333333f;
    float wdOne = 0.027777778;
    float jdOne = 0.027777778;

    for(float i=-90;i<90+step;i+=step){
        r1 = (float)cos(i * MATH_PI / 180.0);
        r2 = (float)cos((i + step) * MATH_PI / 180.0);
        h1 = (float)sin(i * MATH_PI / 180.0);
        h2 = (float)sin((i + step) * MATH_PI / 180.0);
        // 固定纬度, 360 度旋转遍历一条纬线
        float step2=2*step;

        jd = 0;
        for (float j = 0.0f; j <360.0f+step; j +=step2 ) {
            cosV = (float) cos(j * MATH_PI / 180.0);
            sinV = -(float) sin(j * MATH_PI / 180.0);

            data[index++] = r1 * cosV;
            data[index++] = h1;
            data[index++] = r1 * sinV;

//            LOG_DEBUG("SampleTextureSphere::i:%f j:%f x:%f y:%f z:%f\n", i, j, r1 * cosV, h1, r1 * sinV);

            data[index++] = r2 * cosV; //
            data[index++] = h2;
            data[index++] = r2 * sinV;
//            LOG_DEBUG("SampleTextureSphere::i:%f j:%f x:%f y:%f z:%f\n", i, j, r2 * cosV, h2, r2 * sinV);

            m_TextureArray[textureIndex++] = jd * jdOne;
            m_TextureArray[textureIndex++] = 1.0f - wd * wdOne;

            if(i<90) {
                m_TextureArray[textureIndex++] = jd * jdOne;
                m_TextureArray[textureIndex++] = 1.0f - (wd+1) * wdOne;
            }else{
                m_TextureArray[textureIndex++] = jd * jdOne;
                m_TextureArray[textureIndex++] = 1.0f - wd * wdOne;
            }
//            index++;
//            index++;
            count++;
            count++;
            jd++;
        }
        wd++;
    }
    LOG_DEBUG("SampleTextureSphere::111 count:%d wd:%d jd:%d\n", count, wd, jd); // 7 13

//    index = 0;
//    float radius = 1.0f;
//    GLfloat* data = new GLfloat[circularPixCount*3];
//    data[index++] = 0.0f;
//    data[index++] = 0.0f;
//    data[index++] = -6.0f;
//    float angDegSpan=360.0f/(circularPixCount - 2);
//
//    for(float i=0;i<360+angDegSpan;i+=angDegSpan){
//        data[index++] = (float) (radius*sin(i*MATH_PI/180.0f));
//        data[index++] = (float)(radius*cos(i*MATH_PI/180.0f));
//        data[index++] = 0.0f;
//    }
//    LOG_DEBUG("SampleTextureSphere::createPositions index:%d \n", index);

    return data;
}

GLfloat*  SampleTextureSphere::createColors() {
    GLfloat* data = new GLfloat[circularPixCount*4];


//    data[index++] = 0.0f;
//    data[index++] = 0.0f;
//    data[index++] = 0.0f;
//    data[index++] = 1.0f;
    int index = 0;
    for(int i=0;i<circularPixCount; i++){
//        if((int)i%3==0) {
            data[index++] = 1.0f;
            data[index++] = 0.0f;
            data[index++] = 0.0f;
            data[index++] = 1.0f;
//        }else if((int)i%3==1) {
//            data[index++] = 0.0f;
//            data[index++] = 1.0f;
//            data[index++] = 0.0f;
//            data[index++] = 1.0f;
//        }else if((int)i%3==2) {
//            data[index++] = 0.0f;
//            data[index++] = 0.0f;
//            data[index++] = 1.0f;
//            data[index++] = 1.0f;
//        }
    }
//    LOG_DEBUG("SampleTextureSphere::createColors index:%d \n", index);

    return data;
}


GLfloat*  SampleTextureSphere::createCircularPositions() {
    int index = 0;
    float radius = 1.0f;
    GLfloat* data = new GLfloat[circularPixCount*3];
    data[index++] = 0.0f;
    data[index++] = 0.0f;
    data[index++] = 0.0f;
    float angDegSpan=360.0f/(circularPixCount - 2);

    for(float i=0;i<360+angDegSpan;i+=angDegSpan){
        data[index++] = (float) (radius*sin(i*MATH_PI/180.0f));
        data[index++] = (float)(radius*cos(i*MATH_PI/180.0f));
        data[index++] = 0.0f;
    }
    LOG_DEBUG("SampleTextureSphere::createPositions index:%d \n", index);

    return data;
}

GLfloat*  SampleTextureSphere::createCircularColors() {
    GLfloat* data = new GLfloat[circularPixCount*4];
    int index = 0;
    for(float i=0;i<circularPixCount; i++){
        data[index++] = 1.0f;
        data[index++] = 0.0f;
        data[index++] = 0.0f;
        data[index++] = 1.0f;
    }
    LOG_DEBUG("SampleTextureSphere::createColors index:%d \n", index);

    return data;
}

void SampleTextureSphere::UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio)
{
    LOGCATE("SampleTextureSphere::UpdateMVPMatrix angleX = %d, angleY = %d, ratio = %f", angleX, angleY, ratio);
    angleX = angleX % 360;
    angleY = angleY % 360;

    //转化为弧度角
    float radiansX = static_cast<float>(MATH_PI / 180.0f * angleX);
    float radiansY = static_cast<float>(MATH_PI / 180.0f * angleY);


    // Projection matrix
    glm::mat4 Projection = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.1f, 100.0f);
    //glm::mat4 Projection = glm::frustum(-ratio, ratio, -1.0f, 1.0f, 4.0f, 100.0f);
    //glm::mat4 Projection = glm::perspective(45.0f,ratio, 0.1f,100.f);

    // View matrix
    glm::mat4 View = glm::lookAt(
            glm::vec3(0, 0, 4), // Camera is at (0,0,1), in World Space
            glm::vec3(0, 0, 0), // and looks at the origin
            glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
    );

    // Model matrix
    glm::mat4 Model = glm::mat4(1.0f);
    Model = glm::scale(Model, glm::vec3(m_ScaleX, m_ScaleY, 1.0f));
    Model = glm::rotate(Model, radiansX, glm::vec3(1.0f, 0.0f, 0.0f));
    Model = glm::rotate(Model, radiansY, glm::vec3(0.0f, 1.0f, 0.0f));
    Model = glm::translate(Model, glm::vec3(0.0f, 0.0f, 0.0f));

    mvpMatrix = Projection * View * Model;

}